/**
 * Это класс виджета всплывающего меню.
 * Copyright 2012, Alexander Dashkovsky
 * License: http://www.opensource.org/licenses/mit-license.php
 * @lends widget.PopupMenu
 */
widget.PopupMenu = widget.Control.extend({

	/** @const */
	WIDGET_CLASS : 'wg_popupmenu',
	
	/**
	 * Конструктор класса
	 * @augments widget.Control
	 * @class Класс виджета всплывающего меню.
	 * Элементами списка меню могут быть только текстовые строки.
	 * После выбора одного из элементов, меню скрывается.
	 * 
	 * <p><b>CSS класс для DOM элемента - <code>wg_popupmenu</code></b></p>
	 * 
	 * <p><b>Параметры объекта конфигурации:</b></p>
	 * {String} <b>id</b> - Идентификатор компонента PopupMenu.<br/>
	 * {String} <b>cls</b> - Имя класса css (или нескольких классов через пробел)
	 * которые будут добавлены к PopupMenu.<br/>
	 * {Int} <b>width</b> - Ширина компонента.<br/>
	 * {Object[]} <b>items</b> - Массив объектов выбора.
	 * <div class="shift1">{String} <b>items[i].value</b> - Уникальное значение объекта выбора.</div>
	 * <div class="shift1">{String} <b>items[i].text</b> - Текст объекта выбора.</div>
	 * {ElementDOM} <b>renderTo</b> - Элемент DOM, в который будет прорисована кнопка.<br/>
	 * {Object[]} <b>listeners</b> - Массив слушателей событий.<br/>
	 * 
	 * <p><b>События:</b></p>
	 * <div><b>afterrender</b> - Вызывается сразу после прорисовки поля.</div>
	 * <div class="shift1">callbackFunction(<b>component</b>, <b>domElement</b>), где:</div>
	 * <div class="shift2"><b>component</b> - компонент поля.</div>
	 * <div class="shift2"><b>domElement</b> - DOM элемент поля.</div>
	 * <div><b>select</b> - Вызывается при выборе из списка нового эламента.</div>
	 * <div class="shift1">callbackFunction(<b>component</b>, <b>item</b>, <b>optionData</b>), где:</div>
	 * <div class="shift2"><b>component</b> - компонент поля</div>
	 * <div class="shift2"><b>item</b> - запись выбранного элемента из списка.</div>
	 * <div class="shift2"><b>optionData</b> - дополнительные данные, которые связаны с 
	 * контекстным меню. Например, для контекстного меню виджета Grig это будет массив 
	 * элементов строки таблицы над которой была нажата правая кнопка мышки.</div>
	 * <div><b>hide</b> - Вызывается когда кнопка была спрятана.</div>
	 * <div class="shift1">callbackFunction(<b>component</b>, <b>domElement</b>), где:</div>
	 * <div class="shift2"><b>component</b> - компонент кнопки</div>
	 * <div class="shift2"><b>domElement</b> - DOM элемент кнопки</div>
	 * <div><b>show</b> - Вызывается когда кнопка была показана.</div>
	 * <div class="shift1">callbackFunction(<b>component</b>, <b>domElement</b>), где:</div>
	 * <div class="shift2"><b>component</b> - компонент кнопки</div>
	 * <div class="shift2"><b>domElement</b> - DOM элемент кнопки</div>
	 * 
	 * <p><b>Пример:</b></p>
	 * <pre class="code">
	 * var menu = new widget.PopupMenu({
	 *     id : 'm1',
	 *     width : 100,
	 *     cls : 'content',
	 *     items : [
	 *         { value:1, text:'Котлета'},
	 *         { value:2, text:'Шашлык'},
	 *         { value:3, text:'Голубцы'},
	 *         { value:4, text:'Антрекот'}
	 *     ],
	 *     listeners : {
	 *         select : function(menu, item){
	 *             alert('Выбрано "'+item.text+'"');
	 *         }
	 *     }
	 * });
	 * </pre>
	 * 
	 * @constructs
	 * @param {object} config Конфигурационный объект компонента.
	 */
	constructor : function(config) {
		this.config = config || {} ;
		this.base(this.config.id, this.WIDGET_CLASS,
				this.config.label, this.config.value);
	},
	
	/**
	 * Выполняется отрисовка поля.
	 * @public 
	 * @function
	 * @memberOf widget.PopupMenu#
	 * @param {elementDOM} renderTo Элемент DOM, внутри которого будет создано поле.
	 * Если этот параметр не задавать, а поле уже ранее прорисовывалось, то оно 
	 * будет перерисоваться в тот же контейнер. Если в контейнере существуют и 
	 * другие виджеты, render() без параметра прорисует этот виджет после всех 
	 * остальных.
	 * @param {Object} optionData Необязательный параметр. Данные которые будут
	 * возращениы после выбора элемента меню callback-функции на событие select.
	 * @return none
	 */
	render : function(position, optionData) {
		var me = this;
		var renderTo = $('body');
		if (this.element) {
			this.element.remove();
		}
		
        var tpl = '<div class="' + this.WIDGET_CLASS + '" id="' + this.getId() + '"><ul>';
		if (this.config.items) {
			for (var i=0; i<this.config.items.length; i++) {
				var item = this.config.items[i];
				tpl += '<li value="'+item.value+'""><a href="#">'+item.text+'</a></li>';
			}
			
		}
		tpl += '</ul></div>';
		
		if (this.element) {
			this.element.remove();
		}
		this.element = $(tpl);
		if (this.config.cls) {
			this.applyClassToElement(this.config.cls, this.element)
		}

		$(this.element).appendTo(renderTo);
		this.menuEl = $(this.element).find("ul");
		if (this.config.width) {
			$(this.element).width(this.config.width);
		}
		if (position) {
			$(this.element).offset({top:position.y, left:position.x});
		}
		
		$(this.menuEl).menu({
			select: function(event, ui) {
				me.onSelect(event, ui, optionData);
				event.preventDefault();
				return false;
			},
			focus: function(event, ui) {
				me.focus = ui;
			},
			blur: function(event, ui) {
				me.focus = false;
			}
		});

		$('body').bind('click', function(event){
			if (me.focus) {
				var ui = me.focus;
				me.onSelect(event, ui, optionData);
			} else {
				$(me.element).remove();
			}
			$('body').unbind('click');
			event.preventDefault();
			return false;
		});

			
		this.onAfterRender();
	},
	
	/**
	 * Функция отрабатывает сразу после прорисовки конпонента. 
	 * @private 
	 * @function
	 */
	onAfterRender : function() {
		if (this.config.listeners && this.config.listeners.afterrender) {
			this.config.listeners.afterrender(this, this.element);
		}
	},
	
	/**
	 * Функция отрабатывает сразу после выбора любого элемента из списка. 
	 * @private 
	 * @function
	 */
	onSelect : function(event, ui, optionData) {
		this.selectedItem = null;
		var val = $(ui.item[0]).attr('value');
		for (var i=0; i<this.config.items.length; i++) {
			var item = this.config.items[i];
			if (val == item.value) {
				this.selectedItem = item;
				break;
			}
		}
		this.setValue(val);
		if (this.config.listeners && this.config.listeners.select) {
			this.config.listeners.select(this, this.selectedItem, optionData);
		}
		$('body').unbind('click');
		$(this.element).remove();
		this.focus = false;
	},
	
	/**
	 * Спрятать поле 
	 * @public 
	 * @function
	 * @memberOf widget.PopupMenu#
	 */
	hide : function() {
		var oldVisible = this.visible; 
		this.visible = false;
		if (this.visible != oldVisible) {
			this.element.addClass("hidden");
			this.onHide();
		}
	},
	
	/**
	 * Показать поле 
	 * @public 
	 * @function
	 * @memberOf widget.PopupMenu#
	 */
	show : function() {
		var oldVisible = this.visible; 
		this.visible = true;
		if (this.visible != oldVisible) {
			this.element.removeClass("hidden");
			this.onShow();
		}
	},
	
	/**
	 * Функция отрабатывает после того, как элемент будет спрятан. 
	 * @private 
	 * @function
	 */
	onHide : function() {
		if (this.config.listeners && this.config.listeners.hide) {
			this.config.listeners.hide(this, this.element);
		}
	},
	
	/**
	 * Функция отрабатывает после того, как элемент будет показан. 
	 * @private 
	 * @function
	 */
	onShow : function() {
		if (this.config.listeners && this.config.listeners.show) {
			this.config.listeners.show(this, this.element);
		}
	}

});
